// Copyright 2011, Vanya Davidenko.
// Кодировка файла: UTF-8. 
package info.iu9.red;



import info.iu9.TimeLabel;

public class Regex {
  public Regex(final String pattern) {
    final Parser p = new Parser(pattern);
    fa_ = p.parse();
    faa_ = new FiniteAutomataAnalyzer(fa_);

    dfa_ = new DfaInterpreter(fa_, faa_.fact_map(), faa_.max_fact_num());
    nfa_ = new NfaInterpreter(fa_, faa_.num_submatches());
  }

  // Проверка соответствия строки шаблону, заданному регулярным выражением.
  public boolean matches(final String string) {
    return dfa_.matches(string);
  }

  // Проверка присутвия в строке подстроки,
  // соответствующей шаблону, заданному регулярным выражением.
  public boolean contains(final String string) {
    return dfa_.contains(string);
  }

  // Поиск подстроки, соответствующей заданному регулярному выражению,
  // с захватом подстрок группирующими скобками.
  // @retval null в случае contains(string) == false
  public Submatch[] search(final String string) {
    final Submatch dfa_submatch = dfa_.search(string);

    if ( dfa_submatch == null ) {
      return null;
    }

    final Submatch[] result = new Submatch[faa_.num_submatches() + 1];
    result[0] = dfa_submatch;

    if ( dfa_submatch.isEmpty() ) {
      for ( int i = 1 ; i != result.length ; i++) {
        result[i] = dfa_submatch;
      }
      return result;
    }

    if ( faa_.dfa_is_enough() ) {
      assert faa_.num_submatches() <= 1;
      if ( faa_.num_submatches() == 1 ) {
        result[1] = dfa_submatch;
      }
      return result;
    }

    final int b = dfa_submatch.begin();
    final int e = dfa_submatch.end();

    final Submatch[] nfa_submatches = nfa_.search(string, b, e);
    assert nfa_submatches.length == result.length - 1;
    System.arraycopy(nfa_submatches, 0, result, 1, nfa_submatches.length);

    return result;
  }

  public static void main(final String[] args) {
    final StringBuilder string_sb = new StringBuilder();
    for ( int i = 0 ; i != 80000 * 100 ; i++ ) {
      string_sb.append("abcdefghijklmnopqrstuvwxyz");
      //string_sb.append("aaaaaaaaaaaaaaaaaaaaaaaaaa");
    }

    final String pattern = "[a-z][b][ -~*]*";
    final String string = string_sb.toString();

    //Pattern.compile(pattern).matcher(string).matches();

    try {
      final Regex regex = new Regex(pattern);
      System.out.print(regex.fa_.toDot());

      TimeLabel tl = new TimeLabel();
      tl.start();
      final boolean m = regex.matches(string);
      tl.stop();

      System.out.print(!m ?
                       "Not matches" :
                       "Matches: ");
      System.out.print(tl.seconds());

    } catch(RegexException e) {
      e.printStackTrace();
      System.out.print("Parsing failed on " + pattern);

    } catch(RuntimeException e) {
      e.printStackTrace();
      System.out.print("Interpretation failed " + pattern);
    }
  }

  private final FiniteAutomata fa_;
  private final FiniteAutomataAnalyzer faa_;
  private final DfaInterpreter dfa_;
  private final NfaInterpreter nfa_;
}
